#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <queue>
#define default 5
template <typename T>
class BlockQueue
{
    public:
    bool IsFull()
    {
        return _bqueue.size() >= _cap;
    }

    bool IsEmpty()
    {
        return _bqueue.empty();
    }

    BlockQueue(int cap = default)
        :_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond , nullptr);
        pthread_cond_init(&_ccond , nullptr);
    }

    ~BlockQueue()
    {
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }

    void Equeue(T in)
    {
        pthread_mutex_lock(&_mutex);
        while(IsFull())
        {
            _pwait++;
            pthread_cond_wait(&_pcond ,&_mutex);
            std::cout << "一个消费者被唤醒" <<std::endl;
            _pwait--;
        }
        _bqueue.push(in);
        if(_pwait >= 0)
        {
            pthread_cond_signal(&_ccond);
        }
        pthread_mutex_unlock(&_mutex);
    }

    T Pop()
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            _cwait++;
            pthread_cond_wait(&_ccond , &_mutex);
            std::cout << "一个生产者被唤醒" <<std::endl;
            _cwait--;
        }
        T data = _bqueue.front();
        _bqueue.pop();
        if(_cwait >= 0)
        {
            pthread_cond_signal(&_pcond);
        }
        pthread_mutex_unlock(&_mutex);
        return data;
    }

    private:
    int _cap;
    std::queue<T> _bqueue;
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;
    pthread_cond_t _ccond;
    unsigned int _cwait;
    unsigned int _pwait;
};